package test.unit {
	import net.digitalprimates.fluint.sequence.SequenceCaller;
	import net.digitalprimates.fluint.sequence.SequenceWaiter;
	import net.digitalprimates.fluint.sequence.SequenceRunner;
	import com.zanshine.benchmark.core.BenchmarkCase;
	import com.zanshine.benchmark.api.Benchmarkable;
	import com.zanshine.benchmark.core.CaseRunner;
	import com.zanshine.benchmark.core.TestResult;
	import com.zanshine.benchmark.core.events.BenchmarkEvent;
	import com.zanshine.benchmark.core.events.ResultEvent;
	
	import flash.utils.getQualifiedClassName;
	
	import mx.utils.StringUtil;
	
	import net.digitalprimates.fluint.tests.TestCase;
	
	import test.mock.BenchTestMock;

	public class CaseRunnerTest extends TestCase
	{
		private var benchTest:Benchmarkable;
		private var benchRunner:CaseRunner;
		
		override protected function setUp():void
		{
			benchTest = new BenchTestMock;
			//describe = describeType(benchTest);
			benchRunner = new CaseRunner(benchTest);
		}
		
		/**
		 * 
		 */
		public function testResultsLength():void
		{
			benchRunner.addEventListener(
				BenchmarkEvent.CASE_RUNNED, 
				asyncHandler(async_testResultsLength, 50)
			);
			benchRunner.run();
		}
		
		private function async_testResultsLength(event:BenchmarkEvent, data:Object):void
		{
			assertEquals(3, (event.target as CaseRunner).results.length);			
		}
		
		/**
		 * 
		 */
		public function testBenchMethodsCall():void
		{
			benchRunner.addEventListener(
				BenchmarkEvent.CASE_RUNNED, 
				asyncHandler(async_testBenchMethodsCall, 50)
			);
			benchRunner.run();
		}
		
		private function async_testBenchMethodsCall(event:BenchmarkEvent, data:Object):void
		{			
			assertEquals(3, BenchTestMock(benchTest).runnedMethods.length);
		}
		
		/**
		 * 
		 */
		public function testResultsContainBenchResultObjects():void
		{
			benchRunner.addEventListener(
				BenchmarkEvent.CASE_RUNNED, 
				asyncHandler(async_testResultsContainBenchResultObjects, 50)
			);
			benchRunner.run();
		}
		
		private function async_testResultsContainBenchResultObjects(event:BenchmarkEvent, data:Object):void
		{			
			var message:String = "expected results to contain BenchResult objects but was {0}";
			var result:*;
			for each (result in (event.target as CaseRunner).results)
			{
				assertTrue(
					StringUtil.substitute(message, getQualifiedClassName(result)), 
					result is TestResult
				);
			}
		}
		
		/**
		 * 
		 */
		public function testResultIsEmptyBeforeRunningBenchs():void
		{
			assertEquals(0, benchRunner.results.length);
		}
		
		/**
		 * Test that the benchRunner dispatch correct events.
		 */
		 
		public function testDispatchTestMethodEndEvent():void
		{
			benchRunner.addEventListener(
				BenchmarkEvent.TEST_RUNNED, 
				asyncHandler(new Function, 50)
			);
			benchRunner.run();
		}
		
		public function testDispatchBenchTestEndEvent():void
		{
			benchRunner.addEventListener(
				BenchmarkEvent.CASE_RUNNED, 
				asyncHandler(new Function, 50)
			);
			benchRunner.run();
		}
		
		public function testDispatchResultEvent():void
		{
			benchRunner.addEventListener(
				ResultEvent.RESULT,
				asyncHandler(new Function, 50)
			);
			benchRunner.run();
		}
		 
		/**
		 * 
		 * Test that the benchRunner dispatch the correct number of event during the live cycle of the test.
		 * 
		 */
		public function testTestMethodEndEventCount():void
		{
			benchRunner.addEventListener(BenchmarkEvent.TEST_RUNNED, onTestMethodEnd);
			benchRunner.addEventListener(BenchmarkEvent.CASE_RUNNED, asyncHandler(async_testTestMethodEndEventCount, 50) );
			benchRunner.run();
		}
		
		private var testMethodEndEventCount:uint = 0;
		private function onTestMethodEnd(event:BenchmarkEvent):void
		{
			testMethodEndEventCount++;
		}
		
		private function async_testTestMethodEndEventCount(event:BenchmarkEvent, data:Object):void
		{
			assertEquals(BenchTestMock.METHODS_COUNT, testMethodEndEventCount);
		}
		
		
		/**
		  * The tests methods MUST be run in BenchmarkRunner one after each other.
		 */
		
		private var countMock:Mock = new Mock;
		public function testSequencedRunOfTestMethods() : void
		{
			var cRunner:CaseRunner = new CaseRunner(countMock);
			
			var sequence:SequenceRunner = new SequenceRunner(this);
			
			sequence.addStep(new SequenceWaiter(cRunner, ResultEvent.RESULT, 50));
			sequence.addStep(new SequenceCaller(this, assertFirstStep));
			
			sequence.addStep(new SequenceWaiter(cRunner, ResultEvent.RESULT, 50));
			sequence.addStep(new SequenceCaller(this, assertSecondStep));
			
			sequence.addStep(new SequenceWaiter(cRunner, ResultEvent.RESULT, 50));
			sequence.addAssertHandler(assertThirdStep, {});
			
			sequence.run();
			cRunner.run();
		}
		
		private function assertFirstStep():void
		{
			assertEquals(1, countMock.count);
		}

		private function assertSecondStep():void
		{
			assertEquals(2, countMock.count);
		}

		private function assertThirdStep(event:*, data:*):void
		{
			assertEquals(3, countMock.count);
		}
	}
}

import com.zanshine.benchmark.core.BenchmarkCase;

class Mock extends BenchmarkCase
{
	public var count:uint = 0;
	
	public var firstMethodRunned:Boolean;
	[Benchmark]
	public function firstMethod():void
	{
		if(!firstMethodRunned)
		{
			count++;
			firstMethodRunned = true;
		}
	}

	public var secondMethodRunned:Boolean;
	[Benchmark]
	public function secondMethod():void
	{
		if(!secondMethodRunned)
		{
			count++;			
			secondMethodRunned = true;
		}
	}

	public var thirdMethodRunned:Boolean;
	[Benchmark]
	public function thirdMethod():void
	{
		if(!thirdMethodRunned)
		{
			count++;			
			thirdMethodRunned = true;
		}
	}
}